package com.moranyunxi.www.util;

import com.moranyunxi.www.entity.ArticleInfoTemp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriverService;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
public class PhantomJsUtil {

    /**
     * 利用 PhantomJS 工具爬取 html 页面
     * @param url 链接地址
     * @return html 页面文本
     * @throws Exception
     */
    public static String getPageSource(String url) {
        // html 页面
        String pageSource = "";
        //设置必要参数
        DesiredCapabilities dcaps = new DesiredCapabilities();
        //ssl证书支持
        dcaps.setCapability("acceptSslCerts", true);
        //截屏支持
        dcaps.setCapability("takesScreenshot", true);
        //css搜索支持
        dcaps.setCapability("cssSelectorsEnabled", true);
        //js支持
        dcaps.setJavascriptEnabled(true);
        //驱动支持（第二参数表明的是你的phantomjs引擎所在的路径）
        dcaps.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, "/usr/bin/phantomjs");

        PhantomJSDriver driver = null;
        try {
            //创建无界面浏览器对象
            driver = new PhantomJSDriver(dcaps);

            //设置隐性等待（作用于全局）
            driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);

            //打开页面
            driver.get(url);
            Thread.sleep(5000);
            pageSource = driver.getPageSource();
        } catch (Exception e) {

        } finally {
            if (driver != null) {
                driver.quit();// 退出
            }
        }
        return pageSource;
    }

    public static ArticleInfoTemp getWeiXinPage(String weiXinPageUrl) {
        if (!StringUtils.isNotBlank(weiXinPageUrl) || !weiXinPageUrl.contains("mp.weixin.qq.com")) {
            return null;
        }

        Map<String, String> map = new ConcurrentHashMap<>();
        weiXinPageUrl = weiXinPageUrl.trim().replaceAll("\"", "");

//        String webContent = getPageString(weiXinPageUrl);
        String webContent = getPageSource(weiXinPageUrl);
//        String webContent = ChromeUtil.getPageSource(weiXinPageUrl);
        //替换微信img
        webContent = replaceImgSrcFromDataSrc(webContent, map);
        webContent = replaceAudioFromMpvoice(webContent, map);

        Document document = Jsoup.parseBodyFragment(webContent);


        Element ele = document.getElementById("js_content");//当根据id取单个元素的时候
        if (ele == null) {
            return null;
        }

        ArticleInfoTemp bArticleInfo = new ArticleInfoTemp();

        String title = document.select("meta[property=\"og:title\"]").attr("content");
        bArticleInfo.setArticleTitle(title);
        log.info("[title] = " + title);

        String desc = document.select("meta[property=\"og:description\"]").attr("content");
        bArticleInfo.setArticleDesc(desc);
        log.info("[desc] = " + desc);

        String image = document.select("meta[property=\"og:image\"]").attr("content");
//        String imgUrl = getImg(image, map);
        bArticleInfo.setArticleImgUrl(image);
        log.info("[image] = " + image);

        /*Elements elev = document.getElementsByClass("rich_media_content");//当根据类名之类,取多个元素的时候
        if (elev.isEmpty()) { //eles类似于集合,所以用权isEmpty来判断
            //提取视频元素
            String reg = "url: 'http://mpvideo.qpic.cn/";
            if (document.toString().contains(reg)) {
                Document doc = Jsoup.parseBodyFragment("<div id=\"js_content\"><p id=\"js_common_share_desc\">JS_COMMON_SHARE_DESC</p></div>".replace("JS_COMMON_SHARE_DESC", desc));
                doc.attr("style", "max-width: 100%;");

                String videoName = getVideo(weiXinVideoPage(document), map);
                doc.prepend("<video controls=\"controls\" width=\"800\" height=\"\"> <source src='http://www.viedo.com.cn/movie.mp4' type=\"video/mp4\" /> </video>"
                        .replace("http://www.viedo.com.cn/movie.mp4", videoName));//在div前添加html内容

                bArticleInfo.setArticleContent(doc.toString());
            }
//            yesThreadMap_MicroService(map);
            return bArticleInfo;
        }*/

        Document htmlDoc = Jsoup.parse(webContent);
        //获取替换后的 iframe
        htmlDoc = weiXinVideoPageIframe(htmlDoc, map, weiXinPageUrl);

        //获取替换后的div
        Element headDiv = htmlDoc.select("div#js_content").first();
        headDiv.attr("style", "max-width: 100%;");

        bArticleInfo.setArticleContent(headDiv.toString());

//        yesThreadMap_MicroService(map);
        return bArticleInfo;
    }

    /**
     * 获取网页
     *
     * @param uri
     * @return
     * @throws IOException
     */
    private static String getPageString(String uri) {
        String dataSrc = uri;
        //获取网页内容
        String jsonStr = "";
        try {
            jsonStr = Jsoup.connect(dataSrc).ignoreContentType(true).execute().body();
        } catch (IOException ex) {

        } finally {
            return jsonStr;
        }
    }

    /**
     * 将htmlBody中所有img标签中的src内容替换为原data-src的内容,
     * <br/>如果不报含data-src,则src的内容不会被替换
     * <br/>例如:
     * <br/> 替换前 &lt;img data-src="weixinImgUrl" src="localImgUrl" othreAttr="其他属性不变"/&gt;
     * <br/> 替换后 &lt;img src="weixinImgUrl" othreAttr="其他属性不变" /&gt;
     *
     * @param htmlBody
     * @return 返回替换后的内容
     */
    private static String replaceImgSrcFromDataSrc(String htmlBody, Map<String, String> map) {
        Document document = Jsoup.parseBodyFragment(htmlBody);

        Elements nodes = document.select("img");
        int nodeLength = nodes.size();
        for (int i = 0; i < nodeLength; i++) {
            Element e = nodes.get(i);
            String dataSrc = e.attr("data-src");
            if (StringUtils.isNotBlank(dataSrc)) {
                //替换图片为自己的
                e.attr("src", dataSrc);
                e.removeAttr("data-src");
            }
        }

        if (htmlBody.contains("<html>")) {
            return document.toString();
        } else {
            return document.select("body>*").toString();
        }
    }

    /**
     * 将htmlBody中所有mpvoice标签替换为audio,
     *
     * @param htmlBody
     * @return 返回替换后的内容
     */
    private static String replaceAudioFromMpvoice(String htmlBody, Map<String, String> map) {
        String url = "http://res.wx.qq.com/voice/getvoice?mediaid=MEDIA_ID";

        Document document = Jsoup.parseBodyFragment(htmlBody);

        Elements nodes = document.select("mpvoice");
        int nodeLength = nodes.size();
        for (int i = 0; i < nodeLength; i++) {
            Element e = nodes.get(i);

            String urlID = e.attr("voice_encode_fileid");

            if (StringUtils.isNotBlank(urlID)) {
                String result = url.replace("MEDIA_ID", urlID);
                //替换为自己的
//                result = getAudio(result, map);
                e.wrap("<audio  src=\"https://res.wx.qq.com/voice/getvoice\" controls style=\"display: inline\"></audio>".replace("https://res.wx.qq.com/voice/getvoice", result));//在div前添加html内容

            }
        }

        if (htmlBody.contains("<html>")) {
            return document.toString();
        } else {
            return document.select("body>*").toString();
        }
    }

    /**
     * 接口一：视频播放的 iframe 原地址
     * 请求方式：GET
     * 参数：vid：微信视频ID
     * http://mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&auto=0&vid=wxv_1219759656583774208
     * <p>
     * 接口二：请求视频接口,获取视频 url
     * 请求方式：POST
     * 参数：vid：微信视频ID
     * http://mp.weixin.qq.com/mp/videoplayer?action=get_mp_video_play_url&preview=0&__biz=&mid=&idx=&vid=wxv_1219759656583774208&uin=&key=&pass_ticket=&wxtoken=&appmsg_token=&x5=0&f=json
     *
     * @param document
     * @return
     */
    private static Document weiXinVideoPageIframe(Document document, Map<String, String> map, String weiXinPageUrl) {
        String url = "http://mp.weixin.qq.com/mp/videoplayer?action=get_mp_video_play_url&preview=0&__biz=&mid=&idx=&vid=WXV_WID&uin=&key=&pass_ticket=&wxtoken=&appmsg_token=&x5=0&f=json";

        Elements nodes = document.select("iframe");
        int nodeLength = nodes.size();

        int videoIndex = 0;// 计数
        List<String> videoList = new ArrayList<>();
        if (nodeLength > 0) {
            videoList = getDynamicPageVideo(weiXinPageUrl);
            System.out.println("weiXinPageUrl:"+weiXinPageUrl);
            System.out.println("videoList_Size:"+videoList.size());
            System.out.println(videoList);
        }

        for (int i = 0; i < nodeLength; i++) {
            Element e = nodes.get(i);

            e.attr("src", videoList.get(videoIndex));

            System.out.println("video:"+videoIndex);

            videoIndex++;// 递增
        }

        return document;
    }

    // 用于 List<Map<String, Object>> 排序
    public static Integer getIndexValueInMap(Map<String, Object> map) {
        return (Integer) map.get("index");
    }

    /**
     * 获取动态页面的视频链接
     * @param weiXinPageUrl 链接
     * @return
     */
    public static List<String> getDynamicPageVideo(String weiXinPageUrl) {
//        List<String> videoList = new ArrayList<>();
        // 获取页面的视频链接
        List<String> originalVideoList = parseVideo(weiXinPageUrl);
        // 压缩
        /*if (CollectionUtils.isNotEmpty(originalVideoList) && originalVideoList.size() > 0) {
            for (String link : originalVideoList) {
                String ossVideoLink = "";
                try {
                    ossVideoLink = compressionAndUploadVideo(link);
                } catch (IOException e) {

                }

                if (ossVideoLink.equals("")) {
                    videoList.add(link);// 使用原来的
                } else {
                    videoList.add(ossVideoLink);// 使用新的地址
                }
            }
        }*/
//        return videoList;
        return originalVideoList;
    }

    /**
     * 解析动态 js 页面的视频链接
     * @param weiXinPageUrl 微信链接地址
     * @return html
     */
    public static List<String> parseVideo(String weiXinPageUrl) {
        final String videoElementPrefixName = "<video";// video 标签前缀
        final String iframeElementPrefixName = "<iframe";// iframe 标签前缀

        List<String> videoLinkList = new ArrayList<>();// 最终结果
        List<Map<String, Object>> videoSource = new ArrayList<>();// 主要用于视频排序

        String pageSource = getPageSource(weiXinPageUrl);
        Document document = Jsoup.parse(pageSource);// 解析文本
        Element content = document.select("div#js_content").first();// 解析文本

        // 第一步：解析 video 标签
        int videoOffset = 0;
        Elements videoElements = content.select("video");// video 标签
        if (!videoElements.isEmpty()) {
            for (Element videoElement : videoElements) {
                String src = videoElement.attr("src");// src 属性
                if (StringUtils.isNotBlank(src)) {
                    int index = pageSource.indexOf(videoElementPrefixName, videoOffset);// video 元素的位置

                    Map<String, Object> videoOptions = new HashMap<>();
                    videoOptions.put("index", Integer.valueOf(index));
                    videoOptions.put("src", src.startsWith("//") ? "https:" + src : src);// 以 // 开头的链接，加上 https: 协议头

                    videoSource.add(videoOptions);

                    videoOffset = index + videoElementPrefixName.length();// 偏移量增加
                }
            }
        }

        // 第二步：解析 iframe 标签
        int iframeOffset = 0;
        Elements iframeElements = content.select("iframe");// iframe 标签
        if (!iframeElements.isEmpty()) {
            for (Element iframeElement : iframeElements) {
                String src = iframeElement.attr("src");// src 属性
                if (StringUtils.isNotBlank(src)) {
                    int index = pageSource.indexOf(iframeElementPrefixName, iframeOffset);// iframe 元素的位置

                    Map<String, Object> iframeOptions = new HashMap<>();
                    iframeOptions.put("index", Integer.valueOf(index));
                    iframeOptions.put("src", src.startsWith("//") ? "https:" + src : src);// 以 // 开头的链接，加上 https: 协议头

                    videoSource.add(iframeOptions);

                    iframeOffset = index + iframeElementPrefixName.length();// 偏移量增加
                }
            }
        }

        // 第二步：对结果集排序
        if (!CollectionUtils.isEmpty(videoSource) && videoSource.size() > 0) {
            videoSource.stream().sorted(Comparator.comparing(PhantomJsUtil::getIndexValueInMap2)).collect(Collectors.toList())
                    .forEach(info -> {
                        videoLinkList.add(info.get("src").toString());// 存入集合
                    });
        }

        return videoLinkList;
    }

    // 用于 List<Map<String, Object>> 排序
    public static Integer getIndexValueInMap2(Map<String, Object> map) {
        return (Integer) map.get("index");
    }
}
